package org.mcjug.locationmailer.activity;

import oauth.signpost.OAuth;

import org.mcjug.locationmailer.R;
import org.mcjug.locationmailer.db.StatusMessageDatabaseHelper;
import org.mcjug.locationmailer.oauth.tokens.OauthActivity;
import org.mcjug.locationmailer.service.LocationService;
import org.mcjug.locationmailer.util.AlarmManagerUtil;
import org.mcjug.locationmailer.util.Constants;
import org.mcjug.locationmailer.util.EmailUtil;
import org.mcjug.locationmailer.util.ExceptionUtil;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.database.Cursor;
import android.database.sqlite.SQLiteCursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.TextUtils;
//import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemLongClickListener;

public class LocationMailerActivity extends BaseActivity {
    private static final String TAG = LocationMailerActivity.class.getSimpleName();

    private ListView locationListView;
    private SharedPreferences prefs;

    private StatusMessageDatabaseHelper statusMessageHelper;
    private Cursor cursor;
    private SimpleCursorAdapter cursorAdapter;

    private int locationListDisplaySize;
    private LocationUpdateReceiver locationUpdateReceiver;
    private LocationListViewBinder locationListViewBinder;

    // UI fields for location list
    private static final int[] TO = { R.id.textCreatedDate, R.id.textAddress, R.id.textLatitude, R.id.textLongitude,
            R.id.imageLocationProvider };

    public void onCreate(Bundle savedInstanceState) {
        //Log.d(TAG, "before OnCreate");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.locationmailer);

        // Register for preferences updates
        setupPrefs();

        // Allow user to start/stop email sending
        setupEmailSending();
        //Log.d(TAG, "after OnCreate");
    }

    private void setupPrefs() {
        prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        prefs.registerOnSharedPreferenceChangeListener(new InnerOnSharedPreferenceChangeListener());
    }

    private class InnerOnSharedPreferenceChangeListener implements OnSharedPreferenceChangeListener {
        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            // Location update interval changed
            if (key.equals(Constants.PREFS_LOCATION_UPDATE_INTERVAL_KEY) && isStartSendEmailEnabled()) {
                new AlarmManagerUtil(getApplicationContext()).resetAlarm();
                // Location list display size changed
            } else if (key.equals(Constants.PREFS_LOCATION_LIST_DISPLAY_SIZE_KEY)) {
                updateLocationList();
            } else if (key.equals(Constants.PREFS_SENDER_EMAIL_ADDRESS)) {
                setSenderEmailText();
            }
        }
    }

    private void setUpdateIntervalText() {
        TextView intervalTextView = (TextView) findViewById(R.id.textInterval);
        long interval = new AlarmManagerUtil(getApplicationContext()).getInterval();

        String[] intervalValues = getResources().getStringArray(R.array.locationUpdateIntervalValues);
        String[] intervalStrings = getResources().getStringArray(R.array.locationUpdateIntervals);
        String intervalStr = String.valueOf(interval);
        for (int i = 0; i < intervalValues.length; i++) {
            if (intervalValues[i].equals(intervalStr)) {
                intervalTextView.setText(String.format(getString(R.string.interval), intervalStrings[i]));
                break;
            }
        }
    }

    private void setSenderEmailText() {
        //Log.d(TAG, "before setSenderEmailText");
        TextView textView = (TextView) findViewById(R.id.textSenderEmailAddress);

        String senderEmailAddress = prefs.getString(Constants.PREFS_SENDER_EMAIL_ADDRESS, null);
        //Log.d(TAG, "about to set SenderEmailText to: " + senderEmailAddress);
        String label = "";
        if (senderEmailAddress != null) {
            label = " (" + senderEmailAddress + ")";
        }

        textView.setText(label);

    }

    private void enableEmailSendingCheckbox() {
        boolean canSend = EmailUtil.canSendEmail(prefs);
        CheckBox startSendEmailCheckbox = (CheckBox) findViewById(R.id.startSendEmailCheckbox);
        if (canSend) {
            startSendEmailCheckbox.setEnabled(true);
        } else {
            startSendEmailCheckbox.setEnabled(false);
            startSendEmailCheckbox.setChecked(false);
        }
    }

    private void setupEmailSending() {
        CheckBox startSendEmailCheckbox = (CheckBox) findViewById(R.id.startSendEmailCheckbox);
        startSendEmailCheckbox.setChecked(isStartSendEmailEnabled());
        startSendEmailCheckbox.setOnClickListener(new OnClickListener() {
            public void onClick(View view) {
                CheckBox checkBox = (CheckBox) view;
                if (checkBox.isChecked()) {
                    new AlarmManagerUtil(getApplicationContext()).updateAlarm();
                } else {
                    new AlarmManagerUtil(getApplicationContext()).cancelAlarm();
                }
                Editor editor = prefs.edit();
                editor.putBoolean(Constants.PREFS_START_SENDING_EMAIL_KEY, checkBox.isChecked());
                editor.commit();
            }
        });
    }

    private void setupLocationList() {
        locationListView = (ListView) findViewById(R.id.listLocations);
        locationListView.setOnItemLongClickListener(new OnItemLongClickListener() {
            public boolean onItemLongClick(AdapterView<?> listView, View view, int position, long id) {
                SQLiteCursor cursor = (SQLiteCursor) listView.getItemAtPosition(position);
                displayMap(cursor);
                return false;
            }
        });

        // Max entries to display in location list
        locationListDisplaySize = getLocationListDisplaySize();

        // Location list update receiver
        locationUpdateReceiver = new LocationUpdateReceiver();

        locationListViewBinder = new LocationListViewBinder();

        // Populate the location list
        updateLocationList();
    }

    private void displayMap(SQLiteCursor cursor) {
        String latitude = cursor.getString(cursor.getColumnIndex(Constants.getProperty(this,
                R.string.columnLatitudePreferenceName, R.string.columnLatitudeDefaultValue)));
        String longitude = cursor.getString(cursor.getColumnIndex(Constants.getProperty(this,
                R.string.columnLongitudePreferenceName, R.string.columnLongitudeDefaultValue)));
        if (!TextUtils.isEmpty(latitude) && !TextUtils.isEmpty(longitude)) {
            String geoURI = String.format("geo:%s,%s", latitude, longitude);
            geoURI += "?z=14";
            Uri geo = Uri.parse(geoURI);
            Intent geoMap = new Intent(Intent.ACTION_VIEW, geo);
            startActivity(geoMap);
        }
    }

    private int getLocationListDisplaySize() {
        int displaySize = Constants.LOCATION_LIST_DISPLAY_SIZE_DEFAULT;
        String locationSizeStr = prefs.getString(Constants.PREFS_LOCATION_LIST_DISPLAY_SIZE_KEY,
                String.valueOf(displaySize));
        try {
            displaySize = Integer.parseInt(locationSizeStr);
        } catch (NumberFormatException e) {
        }
        return displaySize;
    }

    public boolean isStartSendEmailEnabled() {
        return prefs.getBoolean(Constants.PREFS_START_SENDING_EMAIL_KEY, false);
    }

    private void checkOAuth(SharedPreferences prefs) {
        String token = prefs.getString(OAuth.OAUTH_TOKEN, "");
        String tokenSecret = prefs.getString(OAuth.OAUTH_TOKEN_SECRET, "");
        if (TextUtils.isEmpty(token) || TextUtils.isEmpty(tokenSecret)) {
            startSignIn();
        }
    }

    private void startSignIn() {
        startActivity(new Intent().setClass(getApplicationContext(), SignInActivity.class).setFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK));
    }

    private void startOAuth() {
        //Log.d(TAG, "before startOAuth");
        startActivity(new Intent().setClass(getApplicationContext(), OauthActivity.class).setFlags(
                Intent.FLAG_ACTIVITY_NEW_TASK));
        finish();
        //Log.d(TAG, "after startOAuth");
    }

    public void onResume() {
        super.onResume();
        //Log.d(TAG, "before Onresume");

        checkNetworkConnection();
        
        // Check Gmail Authorization
        checkOAuth(prefs);

        // Status Message database helper
        statusMessageHelper = new StatusMessageDatabaseHelper(getApplicationContext());

        // Populate location list
        setupLocationList();

        setUpdateIntervalText();

        setSenderEmailText();

        // Register for location updates
        IntentFilter filter = new IntentFilter(LocationService.NEW_LOCATION_INTENT_ACTION);
        registerReceiver(locationUpdateReceiver, filter, LocationService.SEND_LOCATION_NOTIFICATIONS, null);
        enableEmailSendingCheckbox();
        //Log.d(TAG, "after Onresume");
    }
    protected void onPause() {
        //Log.d(TAG, "before Onpause");
        if (cursor != null) {
            //Log.d(TAG, "Onpause killing the cursor");
            stopManagingCursor(cursor);
            cursor.close();
            cursor = null;
        }
        // Unregister the location update receiver
        unregisterReceiver(locationUpdateReceiver);
        super.onPause();
        //Log.d(TAG, "after Onpause");
    }

    protected void onDestroy() {
        super.onDestroy();
        try {
            statusMessageHelper.close();
        } catch (Throwable e) {
            ExceptionUtil.exceptAway(this, e, "Error in onDestroy()", null);
        }
    }

    // Called first time user clicks on the menu button
    public boolean onCreateOptionsMenu(Menu menu) {
        // Create items from locationmailermenu.xml
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.locationmailermenu, menu);
        return true;
    }

    // Called when an options item is clicked
    public boolean onOptionsItemSelected(MenuItem item) {
        try {
            switch (item.getItemId()) {

            // Show Location Preferences screen
            case R.id.locationPrefs:
                startActivity(new Intent(getApplicationContext(), PrefActivity.class)
                        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
                break;

            // Clear Location List
            case R.id.clearLocationList:
                statusMessageHelper.delete();
                updateLocationList();
                break;

            // Email Addresses
            case R.id.emailAddresses:
                startActivity(new Intent(getApplicationContext(), EmailActivity.class)
                        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
                break;

            // Gmail OAuth
            case R.id.gmailOAuth:
                startOAuth();
                break;

            // Admin prefs
            case R.id.adminPrefs:
                startActivity(new Intent(getApplicationContext(), AdminPrefsActivity.class)
                        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
                break;

            // Clear Location List
            case R.id.clearPreferences:
                Editor editor = prefs.edit();
                editor.clear();
                editor.commit();

                startActivity(new Intent(getApplicationContext(), SignInActivity.class)
                        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
                break;

            }
        } catch (Throwable e) {
            ExceptionUtil.exceptAway(this, e, "Error in onOptionsItemSelected(MenuItem item)", null);
        }

        return true;
    }

    // Listens for location updates
    private class LocationUpdateReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            updateLocationList();
        }
    }

    private void updateLocationList() {
        if (cursor != null) {
            stopManagingCursor(cursor);
            cursor.close();
        }

        try {

            // Get the Top N location list entries
            cursor = statusMessageHelper.getStatusMessages(locationListDisplaySize);
            startManagingCursor(cursor);

            String[] FROM = {
                    Constants.getProperty(this, R.string.columnCreatedDatePreferenceName,
                            R.string.columnCreatedDateDefaultValue),
                    Constants.getProperty(this, R.string.columnAddressPreferenceName,
                            R.string.columnAddressDefaultValue),
                    Constants.getProperty(this, R.string.columnLatitudePreferenceName,
                            R.string.columnLatitudeDefaultValue),
                    Constants.getProperty(this, R.string.columnLongitudePreferenceName,
                            R.string.columnLongitudeDefaultValue),
                    Constants.getProperty(this, R.string.columnLocationProviderPreferenceName,
                            R.string.columnLocationProviderDefaultValue) };

            // Setup the adapter
            cursorAdapter = new SimpleCursorAdapter(getApplicationContext(), R.layout.locationrow, cursor, FROM, TO);
            cursorAdapter.setViewBinder(locationListViewBinder);
            locationListView.setAdapter(cursorAdapter);

        } catch (Throwable e) {
            //Log.e(TAG, "updateLocationList getStatusMessages error", e);
            ExceptionUtil.exceptAway(this, e, "getStatusMessages error: ", null);
        }
    }
}